#include "ProductsModel.h"

#include <QBrush>
#include <QFile>
#include <assert.h>
#include <QDebug>
#include "ProductsParser.h"

using namespace ecocity;

const uint ProductsModel::s_columns = 11;

ProductsModel::ProductsModel( const std::vector< Product >& products,
                              QObject *parent )
    : QStandardItemModel( parent )
{
    for ( size_t row = 0; row < products.size( ); ++row )
    {
        add_new_product( products[ row ] );
    }
}

//---------------------------------------------------------------

void
ProductsModel::reset( const std::vector<Product> &products )
{
    // Do not call clear cause columns resize again
    // clear( );
    removeRows( 0, rowCount() );

    for ( size_t row = 0; row < products.size( ); ++row )
    {
        add_new_product( products[ row ] );
    }
}

//---------------------------------------------------------------

QVariant
ProductsModel::headerData( int section, Qt::Orientation orientation, int role ) const
{
    if ( role != Qt::DisplayRole || orientation != Qt::Horizontal )
    {
        return QVariant();
    }

    switch( section )
    {
    case PRODUCT_ID:
        return QString( "id" );

    case PRODUCT_NAME:
        return QString( "Nombre en Factura" );

    case PRODUCT_DESCRIPTION:
        return QString( "Nombre largo" );

    case PRODUCT_PROVIDER:
        return QString( "Proveedor" );

    case PRODUCT_COST_ECOCITY:
        return QString( "Coste Ecocity (sin IVA)" );

    case PRODUCT_TAX_RATE:
        return QString( "I.V.A." );

    case PRODUCT_PROFIT_RATE:
        return QString( "Beneficio" );

    case PRODUCT_PRICE_COOPE:
        return QString( "Coope (sin IVA)" );

    case PRODUCT_PRICE_SHOP:
        return QString( "Tienda (sin IVA)" );

    case PRODUCT_PRICE_END_CUSTOMER:
        return QString( "ConsumidorFinal (sin IVA)" );

    case PRODUCT_PRICE_TYPE:
        return QString( "Por Unidad/Kilo" );

    default:
        return QVariant( );
    }
}

//---------------------------------------------------------------

Qt::ItemFlags
ProductsModel::flags ( const QModelIndex & index ) const
{
    if ( index.column() == PRODUCT_ID
         || index.column() == PRODUCT_PRICE_COOPE
         || index.column() == PRODUCT_PRICE_END_CUSTOMER
         || index.column() == PRODUCT_PRICE_SHOP
         || index.column() == PRODUCT_PROFIT_RATE )
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable; // No editable items
    else
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
}

//---------------------------------------------------------------

Product
ProductsModel::product( const QModelIndex &index ) const
{
    int product_id = data( this->index( index.row( ), PRODUCT_ID ) ).toInt( );
    QString product_name = data( this->index( index.row( ), PRODUCT_NAME ) ).toString( );
    QString product_description = data( this->index( index.row( ), PRODUCT_DESCRIPTION ) ).toString();
    QString proveider = data( this->index( index.row( ), PRODUCT_PROVIDER ) ).toString();
    Proveider product_proveider( proveider );
    float product_price = data( this->index( index.row( ), PRODUCT_COST_ECOCITY ) ).toFloat();
    uint product_tax_rate = data( this->index( index.row( ), PRODUCT_TAX_RATE ) ).toUInt();
    QString price_type = data( this->index( index.row( ), PRODUCT_PRICE_TYPE ) ).toString();
    Product::PRICE_TYPE product_price_type = Product::to_price_type( price_type );
    uint product_profit_rate = data( this->index( index.row( ), PRODUCT_PROFIT_RATE ) ).toUInt();

    Product product( product_id,
                     product_name,
                     product_description,
                     product_proveider,
                     product_price,
                     product_price_type,
                     product_tax_rate,
                     product_profit_rate );

    return product;
}

//---------------------------------------------------------------

std::vector< Product >
ProductsModel::products( ) const
{
    std::vector< Product > products;

    for ( int i = 0; i < rowCount( ); ++i )
    {
        Product producto = product( index( i, PRODUCT_ID ) );

        products.push_back( producto );
    }

    return products;
}

//---------------------------------------------------------------

bool
ProductsModel::add_new_product( const Product& product )
{
    qDebug() << "\nProductModel add new product\n" << endl;

    QList<QStandardItem*> items;

    QStandardItem* item_id = new QStandardItem;
    QStandardItem* item_tax_rate = new QStandardItem;
    QStandardItem* item_profit_rate = new QStandardItem;
    QStandardItem* item_price_coope = new QStandardItem;
    QStandardItem* item_price_shop = new QStandardItem;
    QStandardItem* item_price_end_customer = new QStandardItem;
    QStandardItem* item_price = new QStandardItem;

    item_id->setData( product.id( ), Qt::EditRole );
    item_tax_rate->setData( product.tax_rate( ), Qt::EditRole );
    item_profit_rate->setData( product.profit_rate( ), Qt::EditRole );

    item_price_coope->setData(
                QString::number(
                    product.untaxed_price( Customer::COOPERATIVA ), 'f', 2 ), Qt::EditRole );

    item_price_shop->setData(
                QString::number(
                    product.untaxed_price( Customer::TIENDA ), 'f', 2 ) , Qt::EditRole );

    item_price_end_customer->setData(
                QString::number(
                    product.untaxed_price( Customer::CONSUMIDOR_FINAL ), 'f', 2 ), Qt::EditRole );

    item_price->setData(
                QString::number(
                    product.raw_price( ), 'f', 2 ), Qt::EditRole );

    items << item_id
          << new QStandardItem( product.name( ) )
          << new QStandardItem( product.description( ) )
          << new QStandardItem( product.proveider( ).name( ) )
          << new QStandardItem( Product::to_string( product.price_type( ) ) )
          << item_price
          << item_profit_rate
          << item_tax_rate
          << item_price_coope
          << item_price_shop
          << item_price_end_customer;

    if ( (uint)items.size( ) != s_columns )
    {
        // Ensure you don't forget anything
        assert( 0 );
        return false;
    }

    insertRow( rowCount(), items );

    return true;
}

//---------------------------------------------------------------

void
ProductsModel::save( const QString &file_name ) const
{
    if( file_name.isEmpty( ) )
    {
        return;
    }

    QFile file( file_name );

    if ( !file.open( QIODevice::WriteOnly ) )
    {
        return;
    }

    QTextStream out( &file );

    for ( int row = 0; row < rowCount(); ++row )
    {
        for ( uint column = 0; column < s_columns; ++column )
        {
            switch ( column )
            {
            case PRODUCT_ID:
            case PRODUCT_TAX_RATE:
            case PRODUCT_PROFIT_RATE:
                out << item( row, column )->data( Qt::EditRole ).toInt();
                break;
            case PRODUCT_NAME:
            case PRODUCT_DESCRIPTION:
            case PRODUCT_PROVIDER:
            case PRODUCT_PRICE_TYPE:
                out << item( row, column )->text();
                break;
            case PRODUCT_PRICE_COOPE:
            case PRODUCT_PRICE_SHOP:
            case PRODUCT_PRICE_END_CUSTOMER:
            case PRODUCT_COST_ECOCITY:
                out << item( row, column )->data( Qt::EditRole ).toFloat();
                break;
            default:
                break;
            }

            if ( column < s_columns - 1 )
            {
                out << ",";
            }
        }

        out << "\n";
    }

    file.close();
}

//---------------------------------------------------------------

bool
ProductsModel::load( const QString &file_name )
{
    removeRows( 0, rowCount() );

    clear( );

    if( file_name.isEmpty( ) )
    {
        return false;
    }

    QFile file( file_name );

    if ( !file.open( QIODevice::ReadOnly ) )
    {
        return false;
    }

    QTextStream stream( &file );

    while ( !stream.atEnd() )
    {
        QString line = stream.readLine( );

        while( line.startsWith( '#' ) )
        {
            line = stream.readLine( );
        }

        std::vector<int> separators =
                ProductsParser::separators_in_line( line );

        // list should contain 9 separators
        //      id,Name,Description,Provider,TaxRate,PriceCoope,PriceSHop,PriceCustomer,Price
        // i.e. 1,Pan rustic,Pan rustic eco,La Fogaina, 8%, 30%, 25%, 20%, 2EUR
        if( separators.size() != s_columns )
        {
            assert( 0 );
            return false;
        }

        const Product product = ProductsParser::to_product( line, ';' );

        add_new_product( product );
    }

    file.close();

    return true;
}

//---------------------------------------------------------------

int
ProductsModel::get_biggest_id( )
{
    int max_id = -1;

    for ( int i = 0; i < rowCount( ); ++i )
    {
        int id = data( index( i, PRODUCT_ID ) ).toInt( );

        if ( id > max_id )
        {
            max_id = id;
        }
    }

    return max_id;
}
